/**
  ******************************************************************************
  * @file    UDP_OpenServer.c
  * @author  exatron
  * @version V1.0.0
  * @date    segunda, 22 de dezembro de 2014
  * @brief   Função para abrir um socket server.
  ******************************************************************************
  * @attention
  *
  *
  ******************************************************************************
  */

/** @addtogroup TCP
  * @{
  */

/* Includes ------------------------------------------------------------------*/
#include <common.h>

/* Private variables ---------------------------------------------------------*/
extern Socket_t sock[N_SOCKS];

extern FIFO_t isrx_fifo;

extern BooleanType_t ISRINGS;
extern BooleanType_t ISCLOSE;

/* External functions --------------------------------------------------------*/

/** @defgroup UDP_Functions
  * @{
  */

/**
  * @brief  Função para abrir um socket server.
  * @param  SocketID_t: ID do socket server
  * @param  int porta: Porta a escutar
  * @retval Devolve pela serial Result_t
  */
void UDP_OpenServer(SocketID_t id, int porta)
{
    int i, yes=1;

	/* Se já possuia conexão, fecha*/
	if(sock[id].serfd > 0)
	{
  		/* Fecha sock */
		close(sock[id].serfd);

		/* Informa Desconexão */
		if(ISRINGS == TRUE)
		{
			aux_USART0_puts("%s=%d;%d\r\n", "SCK_CLOS", id, Result_Ok);
		}

		/* Limpa estrutura do socket */
		aux_ClearSocket(id);

	}

    /* Verifica se o socket esta aberto */
    if(sock[id].status != Status_SocketClosed)
    {
		aux_USART0_puts("%s=%d;%d\r\n", "UDP_OPS", id, Result_AlreadyExists);
		aux_SetBusy(FALSE);
		return;
    }

    /* Verifica se a porta ja esta aberta */
    i=0;
    while(i<(N_SOCK_TCP+N_SOCK_UDP))
    {
    	if(sock[i].porta == porta)
    	{
			aux_USART0_puts("%s=%d;%d\r\n", "UDP_OPS", id, Result_PortOpened);
			aux_SetBusy(FALSE);
			return;
    	}
    	i++;
    }

    /* Verifica se possui timeout válido */
    if(aux_CFG_GetTimeOutSocket() == -1)
    {
    	aux_USART0_puts("%s=%d;%d\r\n", "UDP_OPS", id, Result_Error);
    	aux_SetBusy(FALSE);
    	return;
    }

	/* Verifica se esta em rede */
	if(aux_WF_GetIP() != Result_Ok)
	{
		aux_USART0_puts("%s=%d;%d\r\n", "UDP_OPS", id, Result_NoConnection);
		aux_SetBusy(FALSE);
		return;
	}

    /* Zera estrutura do socket */
    aux_ClearSocket(id);

    /* Abre o socket */
    sock[id].serfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sock[id].serfd < 0)
    {
		aux_USART0_puts("%s=%d;%d\r\n", "UDP_OPS", id, Result_OnOpen);
		aux_SetBusy(FALSE);
		return;
    }

    /* Seta id e informações de endereço */
    sock[id].ID = id;
    sock[id].seraddr.sin_port = htons(porta);
    sock[id].seraddr.sin_family = AF_INET;
    sock[id].seraddr.sin_addr.s_addr = INADDR_ANY;	// Pŕoprio IP;

    /* Reutiliza a porta */
    if(setsockopt(sock[id].serfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1)
    {
		aux_USART0_puts("%s=%d;%d\r\n", "UDP_OPS", id, Result_OnSet);
		aux_SetBusy(FALSE);
		return;
    }

    if(bind(sock[id].serfd,(struct sockaddr *)&sock[id].seraddr,sizeof(sock[id].seraddr))<0)
    {
		aux_USART0_puts("%s=%d;%d\r\n", "UDP_OPS", id, Result_OnBinding);
		aux_SetBusy(FALSE);
		return;
    }

    /* Escreve a porta */
    sock[id].porta = porta;

    /* Seta status do socket */
    sock[id].status = Status_SocketConnected;

    /* Escreve o tipo de socket */
    sock[id].type = UDP_SERVER;

    /* Informa Conexão */
    aux_USART0_puts("%s=%d;%d\r\n", "UDP_OPS", id, Result_Ok);

    aux_SetBusy(FALSE);
}

void UDP_OpenServer_recv(SocketID_t id)
{
	char buf_temp[RX_BUF_LEN];
	socklen_t clilen;

	clilen = sizeof(sock[id].cliaddr);

   	bzero(buf_temp, sizeof(buf_temp));
   	if(sock[id].serfd > 0)
   		sock[id].nb_rec = recvfrom(sock[id].serfd, buf_temp, RX_BUF_LEN-1,0,(struct sockaddr *)&sock[id].cliaddr,&clilen);
   	else
   		return;

    if(sock[id].nb_rec > 0)
    {
       	sock[id].istimeout = 0;

    	fifo_write(&sock[id].fifo_rx, buf_temp, sock[id].nb_rec);

    	if(sock[id].isrx == NoRead)
    	{
    		sock[id].isrx = IsRead;
    		fifo_write(&isrx_fifo, &id, 1);
    		if(ISRINGS == TRUE)
    		{
				aux_SendSignal("SCK_IRDR=%d;%d\r\n", sock[id].ID, Result_Ok);
    	}
    	}
    }
   	/* Erro no recebimento */
   	else
   	{
   		/* Fecha sock */
		if(sock[id].serfd > 0)
			close(sock[id].serfd);

		/* Informa Desconexão */
		if(ISRINGS == TRUE || ISCLOSE == TRUE)
		{
			aux_USART0_puts("%s=%d;%d\r\n", "SCK_CLOS", id, Result_Ok);
			ISCLOSE = FALSE;
		}

		/* Limpa estrutura do socket */
		aux_ClearSocket(id);
   	}
}

/**
  * @}
  */

/**
  * @}
  */







